#pragma once

#include <iostream>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>

using namespace std;

#define SEP " "
#define SEP_LEN strlen(SEP)
#define SEP_LINE "\r\n"
#define SEP_LINE_LEN strlen(SEP_LINE)

enum
{
    DIV_ZERO = 1,
    MOD_ZERO,
    OP_ERR,
};

//TODO 加报头 去报头 读取完整报文

//"x op y" -> "length\r\n""x op y\r\n"
//"exitcode result" -> "length\r\n""exitcode result\r\n"
void enLength(const string& text, string* package)
{
    string text_len = to_string(text.size());
    *package += text_len;
    *package += SEP_LINE;
    *package += text;
    *package += SEP_LINE;
}

//"length\r\n""x op y\r\n"
//"length\r\n""exitcode result\r\n" -> "exitcode result"
bool deLength(const string& package, string* text)
{
    int pos = package.find(SEP_LINE);
    if (pos == string::npos)
        return false;
    int text_len = stoi(package.substr(0, pos));
    *text = package.substr(pos + SEP_LINE_LEN, text_len);
    return true;
}

struct Request
{
    Request()
    {}

    Request(int x, int y, char op)
    : _x(x),
      _y(y),
      _op(op)
    {}

    //_x, _y, _op -> "x op y"
    void serialize(string* out)
    {
        *out = "";
        string x_str = to_string(_x);
        string y_str = to_string(_y);
        *out += x_str;
        *out += SEP;
        *out += _op;
        *out += SEP;
        *out += y_str;
    }

    //"x op y" -> _x, _y, _op
    bool deserialize(const string& in)
    {
        int left = in.find(SEP), right = in.rfind(SEP);
        if (left == string::npos || right == string::npos)
            return false;
        if (left == right)
            return false;
        if (right != left + 1 + SEP_LEN)//操作符输入错误
            return false;
        string x_str = in.substr(0, left), y_str = in.substr(right + SEP_LEN);
        if (x_str.empty() || y_str.empty())
            return false;
        _x = stoi(x_str);
        _y = stoi(y_str);
        _op = in[left + SEP_LEN];
        return true;
    }

    int _x;
    int _y;
    char _op;
};

struct Response
{
    Response()
    {}

    Response(int exitcode, int result)
    : _exitcode(exitcode),
      _result(result)
    {}

    //_exitcode, _result -> "exitcode result"
    bool serialize(string* out)
    {
        *out = "";
        string exit_str = to_string(_exitcode);
        string ret_str = to_string(_result);
        *out += exit_str;
        *out += SEP;
        *out += ret_str;
        return true;
    }

    //"exitcode result" -> _exitcode, _result
    bool deserialize(const string& in)
    {
        int pos = in.find(SEP);
        if (pos == string::npos)
            return false;
        string exit_str = in.substr(0, pos);
        string ret_str = in.substr(pos + SEP_LEN);
        if (exit_str.empty() || ret_str.empty())
            return false;
        _exitcode = stoi(exit_str);
        _result = stoi(ret_str);
        return true;
    }

    int _exitcode;
    int _result;
};

bool recvOnePackage(string& inbuffer, string* onePackage)
{
    int pos = inbuffer.find(SEP_LINE);
    if (pos == string::npos)
        return false;
    int text_len = stoi(inbuffer.substr(0, pos));
    int total_len = pos + text_len + 2 * SEP_LINE_LEN;
    if (inbuffer.size() < total_len)
        return false;
    *onePackage = inbuffer.substr(0, total_len);
    inbuffer.erase(0, total_len);
    return true;
}